/*
 * Copyright 2017 Baiyyy
 * @(#)PsZcdHzService.java
 */

package com.byyy.ccts.modules.cc.service.impl;

import com.byyy.ccts.core.common.service.impl.CommonServiceImpl;
import com.byyy.ccts.core.message.rocketmq.OAProducer;
import com.byyy.ccts.core.message.rocketmq.config.Configuration;
import com.byyy.ccts.core.query.wrapper.EntityWrapper;
import com.byyy.ccts.core.utils.*;
import com.byyy.ccts.core.utils.cq.CQAuthenticationUtils;
import com.byyy.ccts.core.utils.http.HttpUtils;
import com.byyy.ccts.modules.api.convert.PsZcdConvert;
import com.byyy.ccts.modules.api.entity.BackTemperatureVo;
import com.byyy.ccts.modules.api.entity.DeliveryVo;
import com.byyy.ccts.modules.cc.entity.ccts.*;
import com.byyy.ccts.modules.cc.entity.vo.CkdInfo;
import com.byyy.ccts.modules.cc.entity.vo.CkdProcess;
import com.byyy.ccts.modules.cc.entity.vo.LmisZcdMxUpdateVo;
import com.byyy.ccts.modules.cc.enums.DeliveryStateEnum;
import com.byyy.ccts.modules.cc.enums.PsStateEnum;
import com.byyy.ccts.modules.cc.enums.WhetherOrNotEnum;
import com.byyy.ccts.modules.cc.enums.WorkingStateEnum;
import com.byyy.ccts.modules.cc.mapper.*;
import com.byyy.ccts.modules.cc.service.IPsZcdMxService;
import com.byyy.ccts.modules.cc.service.IPsZcdService;
import com.byyy.ccts.modules.llcx.entity.LlcxDanw;
import com.byyy.ccts.modules.llcx.service.IDanwService;
import com.byyy.ccts.modules.sys.Constants;
import com.byyy.ccts.modules.sys.service.IParamService;
import com.byyy.ccts.modules.sys.utils.DynamicDBUtils;
import com.byyy.ccts.modules.sys.utils.UserUtils;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.*;

/**
 * Created by DELL on 2018-6-14.
 */
@Transactional
@Service("psZcdService")
public class PsZcdService extends CommonServiceImpl<PsZcdMapper, PsZcdHz> implements IPsZcdService {

    @Autowired
    private PsZcdMxMapper psZcdMxMapper;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private CouvenseMapper couvenseMapper;

    @Autowired
    private ChillCarMapper chillCarMapper;

    @Autowired
    private HumitureMapper humitureMapper;

    @Autowired
    private IPsZcdMxService psZcdMxService;

    @Autowired
    private IParamService paramService;

    @Autowired
    private IDanwService danwService;

    /**
     * 回传启运温度数据
     */
    private static String URL_BACK_TEMPERATURE = JeewebPropertiesUtil.getConfig("cq.ll.confirm.suffix.address");;

    @Override
    public void delivery(DeliveryVo deliveryVo) {
        PsZcdConvert convert = PsZcdConvert.INSTANCE;
        PsZcdHz psZcdHz = convert.deliveryToPsZcdHz(deliveryVo);
        List<PsZcdMx> psZcdMxList = convert.deliveryDetailToPsZcdMxList(deliveryVo.getProductList());

        // 冷链客户生成用户
        List<LlcxDanw> llcxDanwList = convert.deliveryDetailToLlcxDanwList(deliveryVo.getProductList());
        this.danwService.createDanwUser(llcxDanwList);

        // 数据库内如果已确认，那就不让修改了
        PsZcdHz psZcdHzDb = this.selectById(psZcdHz.getZhuangcdNo());
        boolean confirm = DeliveryStateEnum.确认.getValue().equals(psZcdHzDb == null ? null : psZcdHzDb.getDeliveryState());
        if (confirm) {
            return;
        }

        // 先删除，再添加
        this.deleteById(psZcdHz.getZhuangcdNo());
        this.psZcdMxService.delete(new EntityWrapper<PsZcdMx>().eq("mx_zhuangcd_no", psZcdHz.getZhuangcdNo()));
        PsZcdMx mx = null;
        List<PsZcdMx> huozMxList = null;
        Map<String, List<PsZcdMx>> deliveryMap = new HashMap<>(16);
        for (int i = 0; i < psZcdMxList.size(); i++) {
            mx = psZcdMxList.get(i);
            mx.setZhuangcdNo(psZcdHz.getZhuangcdNo());
            mx.setZhuangcdId(mx.getZhuangcdNo() + "_" + i);
            if (deliveryMap.get(mx.getHuozId()) != null) {
                huozMxList = deliveryMap.get(mx.getHuozId());
                huozMxList.add(mx);
            }
            else {
                huozMxList = new ArrayList<>();
                huozMxList.add(mx);
                deliveryMap.put(mx.getHuozId(), huozMxList);
            }
        }

        // 根据货主发送消息
        FreeMarkerUtils utils = FreeMarkerUtils.initByDefaultTemplate();
        Map<String, Object> map = null;
        OAProducer oAProducer = (OAProducer) SpringContextHolder.getBean("oAProducer");
        confirm = DeliveryStateEnum.确认.getValue().equals(psZcdHz.getDeliveryState());
        for (Map.Entry entry : deliveryMap.entrySet()) {
            map = new HashMap<>(2);
            map.put("confirm", confirm);
            map.put("list", (List) entry.getValue());
            oAProducer.sendOAMail("delivery" + entry.getKey(),
                    confirm ? "装车单确认信息" : "装车单下发信息",
                    utils.processToString("deliveryMsg.ftl", map));
        }

        psZcdHz.setOwnFlg(StringUtils.isEmpty(psZcdHz.getTuoyCompany()) ? "Y" : "N");
        this.insert(psZcdHz);
        this.psZcdMxService.insertBatch(psZcdMxList);
    }

    /**
     * 定时同步LMIS冷链装车单数据
     * 1.先从视图中获取尚未同步的装车单明细数据
     * 2.根据装车单号获取装车单汇总数据
     * 3.插入装车单汇总数据
     * 4.插入装车单明细数据
     */
    @Override
    public void syncLmisZcd() {
        // 变量定义
        List<String> zcdNos = new ArrayList<>();
        List<PsZcdMx> zcdMxList = null;
        List<PsZcdHz> zcdHzList = null;

        // 先从视图中获取尚未同步的装车单明细数据
        zcdMxList = this.psZcdMxMapper.getZcdMxFromLmis();
        if (zcdMxList != null && zcdMxList.size() > 0) {
            // 根据装车单号获取装车单汇总数据
            for (PsZcdMx temp : zcdMxList) {
                if (!zcdNos.contains(temp.getZhuangcdNo())) {
                    zcdNos.add(temp.getZhuangcdNo());
                }
            }
            // 逻辑上不可能为空，就不做判断了
            zcdHzList = this.baseMapper.getZcdHzFromLmis(zcdNos);

            // 保存
            this.insertBatch(zcdHzList);
            this.psZcdMxService.insertBatch(zcdMxList);
        }

        // 没有商品存储温度的，根据商品ID更新装车单明细中的商品储存温度
        zcdMxList = this.psZcdMxMapper.queryUpdShangpCondition();
        if (zcdMxList != null && zcdMxList.size() > 0) {
            for (PsZcdMx temp : zcdMxList) {
                if (temp.getWendMin() != null && temp.getWendMax() != null) {
                    this.psZcdMxMapper.updShangpCondition(temp);
                }
            }
        }

    }

    /**
     * 发车确认
     * 1.检查是否都已经关联了设备(装车单状态前端判断过了，后台就不在判断了)
     * 2.修改装车单汇总状态以及明细开始时间
     * 3.修改采集设备以及保温箱状态
     * @param zcdNos
     * @return
     */
    @Override
    public String facConfirm(List<String> zcdNos) {
        // 定义变量
        StringBuilder sb = new StringBuilder();
        List<PsZcdHz> psZcdHzList = null;
        List<PsZcdMx> psZcdMxList = null;
        List<String> cjIds = new ArrayList<>();
        List<String> lcSns = new ArrayList<>();
        List<String> carIds = new ArrayList<>();
        Timestamp now = new Timestamp(System.currentTimeMillis());
        String msgTemplate = null;

        // 为了防止有时候装车确认时，没有将整个冷藏车内的装车单进行发车，所以在此获取冷藏车内其他装车单
        psZcdMxList = this.psZcdMxMapper.selectZcdInCar(zcdNos);
        if (psZcdMxList != null && psZcdMxList.size() > 0) {
            for (PsZcdMx temp : psZcdMxList) {
                if (!zcdNos.contains(temp.getZhuangcdNo())) {
                    zcdNos.add(temp.getZhuangcdNo());
                }
            }
        }

        // 查询装车单明细信息,前端做了空判断，此时一般不会有逻辑错误，故不进行空判断了先
        msgTemplate = "存储温度为{0}-{1},当前设备{2}温度为{3};<br/>";
        List<PsZcdMx> psZcdMxCheckList = this.psZcdMxMapper.selectZcdMxTempByZcdNo(zcdNos);
        StringBuilder tempWarningInfo = new StringBuilder();
        Map<String, Object> zcdMxMap = new HashMap<>();
        for (PsZcdMx temp : psZcdMxCheckList) {
            if (WhetherOrNotEnum.否.getValue().equals(temp.getCarFlag())
                    && (StringUtils.isEmpty(temp.getSbSn())
                        || StringUtils.isEmpty(temp.getBoxSn()))) {
                sb.append("装车单[").append(temp.getZhuangcdNo()).append("]内存在未关联的设备或者保温箱，请确认后重新发车！");
                return sb.toString();
            }

            // 判断是否存在存储温度为空的商品
            if (temp.getWendMin() == null || temp.getWendMax() == null) {
                if (sb.indexOf(temp.getShangpNo()) < 0) {
                    sb.append(temp.getShangpNo()).append(";");
                }
            }

            if (!cjIds.contains(temp.getSbSn())) {
                cjIds.add(temp.getSbSn());
            }
            if (!lcSns.contains(temp.getBoxSn())) {
                lcSns.add(temp.getBoxSn());
            }

            // 判断存储温度是否合格
            if (temp.getTemperature() == null) {
                if (tempWarningInfo.indexOf(temp.getSbNo()) <= 0) {
                    tempWarningInfo.append(MessageFormat.format(msgTemplate, temp.getWendMin(), temp.getWendMax(),
                            temp.getSbNo(), "空"));
                }
                continue;
            }
            if (temp.getTemperature() > temp.getWendMax()
                    || temp.getTemperature() < temp.getWendMin()) {
                if (tempWarningInfo.indexOf(temp.getSbNo()) <= 0) {
                    tempWarningInfo.append(MessageFormat.format(msgTemplate, temp.getWendMin(), temp.getWendMax(),
                            temp.getSbNo(), temp.getTemperature()));
                }
            }

            // 20201014 发车时开始时间默认为最近的设备采集时间,冷藏车除外
            if (WhetherOrNotEnum.是.getValue().equals(temp.getCarFlag())) {
                zcdMxMap.put("BeginDate_" + temp.getZhuangcdId(), now);
            }
            else {
                zcdMxMap.put("BeginDate_" + temp.getZhuangcdId(), temp.getCollectTime());
            }
            zcdMxMap.put("BeginTemp_" + temp.getZhuangcdId(), temp.getTemperature());

        }

        if (StringUtils.isNotEmpty(sb.toString())) {
            sb.append("上述商品未维护存储温度");
            return sb.toString();
        }
        if(!StringUtils.isEmpty(tempWarningInfo.toString())) {
            tempWarningInfo.insert(0, "设备温度不合格<br/>");
            return tempWarningInfo.toString();
        }

        // 查询装车单汇总信息，因为前端判断过状态，此处不再做状态上的判断，同理，前端做过空判断，此处不再判断
        psZcdHzList = this.selectBatchIds(zcdNos);
        psZcdMxList = this.psZcdMxService.selectByZcdNos(zcdNos);
        for (PsZcdHz temp : psZcdHzList) {
            temp.setState(PsStateEnum.激活关联.getValue());
        }

        for (PsZcdMx temp : psZcdMxList) {
            temp.setBeginTemp((Float) zcdMxMap.get("BeginTemp_" + temp.getZhuangcdId()));
            temp.setBeginDate((Timestamp) zcdMxMap.get("BeginDate_" + temp.getZhuangcdId()));
        }

        // 更新状态并保存 设备、保温箱[2：已激活]
        this.updateBatchById(psZcdHzList);
        this.psZcdMxService.updateBatchById(psZcdMxList);
        this.deviceMapper.updateWorkingByIds(cjIds, WorkingStateEnum.已激活.getValue());
        if (lcSns.size() > 0) {
            this.couvenseMapper.updateWorkingByIds(lcSns, WorkingStateEnum.已激活.getValue());
        }
        if (carIds.size() > 0) {
            this.chillCarMapper.updateWorkingByIds(carIds, WorkingStateEnum.已激活.getValue());
        }


        return sb.toString();
    }

    /**
     * 配送交接前的检查工作
     * @param zcdNo
     * @param handOverDate
     * @param danjNos
     * @return
     */
    @Override
    public String beforeHandOver(String zcdNo, Date handOverDate, List<String> danjNos) {
        // 定义变量
        StringBuilder sb = new StringBuilder();
        String msgTemplate = null;
        List<PsZcdMx> zcdMxList = null;

        // 检查交接时间点的温度是否合适
        zcdMxList = this.psZcdMxMapper.selectZcdMxTempByDanjNo(danjNos, handOverDate);
        if (zcdMxList == null || zcdMxList.size() < 1) {
            sb.append("未查询到设备温度信息");
            return sb.toString();
        }

        msgTemplate = "存储温度为{0}-{1},当前设备{2}温度为{3};<br/>";
        for (PsZcdMx temp : zcdMxList) {
            if (temp.getTemperature() == null) {
                if (sb.indexOf(temp.getSbSn()) <= 0) {
                    sb.append(MessageFormat.format(msgTemplate, temp.getWendMin(), temp.getWendMax(),
                            temp.getSbSn(), "空"));
                }
                continue;
            }
            if (temp.getTemperature() > temp.getWendMax()
                    || temp.getTemperature() < temp.getWendMin()) {
                if (sb.indexOf(temp.getSbSn()) <= 0) {
                    sb.append(MessageFormat.format(msgTemplate, temp.getWendMin(), temp.getWendMax(),
                            temp.getSbSn(), temp.getTemperature()));
                }
            }
        }
        if(!StringUtils.isEmpty(sb.toString())) {
            sb.insert(0, "设备温度不合格<br/>");
            sb.append("<font size='3' color='red'>是否执行配送交接</font>");
            return sb.toString();
        }

        return sb.toString();
    }

    /**
     * 配送交接
     * 1.根据装车单号以及单据编号查询装车单明细数据
     * 2.更新装车单结束时间
     * 3.判断是否所有的装车单都已经结束，如果全部结束，更新装车单状态
     * 4.更新采集设备以及保温箱工作状态
     * @param zcdNo
     * @param handOverDate
     * @param danjNos
     * @return
     */
    @Override
    public String handOver(String zcdNo, Date handOverDate, List<String> danjNos) {
        // 定义变量
        StringBuilder sb = new StringBuilder();
        List<PsZcdMx> zcdMxList = null;
        List<PsZcdMx> notFinishedMx = null;
        List<TSHumiture> humitureList = null;
        List<TSHumiture> deviceHumitureList = null;
        List<String> cjIds = new ArrayList<>();
        List<String> lcSns = new ArrayList<>();
        List<String> carIds = new ArrayList<>();
        PsZcdHz zcdHz = null;
        Timestamp endTime = new Timestamp(handOverDate.getTime());
        Timestamp beginTime = null;
        long diff = 0;
        boolean isCar = false;
        int minute = 0;

        // 获取装车单明细数据
        zcdMxList = this.psZcdMxMapper.selectByDanjNos(zcdNo, danjNos);

        // 判断当前交接时间与单据关联的设备的采集时间是否相差太久[以4分钟为准]
        humitureList = this.humitureMapper.queryHumitureByDanjNo(zcdNo, danjNos, handOverDate);
        if (humitureList != null && humitureList.size() > 0) {
            for (TSHumiture temp : humitureList) {
                diff = DateUtils.getSecondOfTwoDate(temp.getCollectTime(), handOverDate);
                if ((diff / 60) > 4) {
                    sb.append("温度设备[").append(temp.getSbNo()).append("]最新温度采集时间为[")
                            .append(DateUtils.formatDate(temp.getCollectTime(), "yyyy-MM-dd HH:mm:ss"))
                            .append("]，据当前交接时间已超过4分钟，请确认！");
                    return sb.toString();
                }

                // 判断每个设备是否数据连续，有断层
                deviceHumitureList = this.humitureMapper.queryDeviceHumitureList(zcdNo, temp.getSbNo(), handOverDate);
                if (deviceHumitureList == null || deviceHumitureList.size() < 1) {
                    sb.append("温度设备[").append(temp.getSbNo()).append("]无在途数据，请确认！");
                    return sb.toString();
                }
                beginTime = deviceHumitureList.get(0).getCollectTime();
                minute = deviceHumitureList.get(0).getMinute();
                diff = DateUtils.getSecondOfTwoDate(beginTime, handOverDate) / 60;
                // 30-34-39：9分钟，应该取3个数
                if ((diff / minute + 1) > deviceHumitureList.size()) {
                    sb.append("温度设备[").append(temp.getSbNo()).append("],需采集").append(diff / minute + 1)
                            .append("条数据,实采集").append(deviceHumitureList.size()).append("条数据,存在温度数据中断,请确认!");
                    return sb.toString();
                }
            }
        }
        else {
            sb.append("没有查询到关联设备的最新时间，请确认！");
            return sb.toString();
        }

        // 设置结束时间并更新 20200117 现在不想拆个方法出来，回头想了再拆
        isCar = WhetherOrNotEnum.否.getValue().equals(zcdMxList.get(0).getCarFlag()) ? false: true;
        if (zcdMxList.get(0).getBeginDate().getTime() - endTime.getTime() > 0) {
            sb.append("单据交接时间不能早于开始时间！");
            return sb.toString();
        }

        for (PsZcdMx temp : zcdMxList) {
            temp.setEndDate(endTime);
            if (!isCar) {
                if (!cjIds.contains(temp.getSbSn())) {
                    cjIds.add(temp.getSbSn());
                }
                if (!lcSns.contains(temp.getBoxSn())) {
                    lcSns.add(temp.getBoxSn());
                }
            }
        }
        this.psZcdMxService.updateBatchById(zcdMxList);

        // 判断是否存在尚未结束的单据
        notFinishedMx = this.psZcdMxMapper.selectNotFinishedMx(zcdNo);
        boolean finashFlg = false;
        // 不存在未结束的单据则修改装车单状态 3：配送完成
        if (notFinishedMx == null || notFinishedMx.size() < 1) {
            zcdHz = this.selectById(zcdNo);
            zcdHz.setState(PsStateEnum.配送完成.getValue());
            this.updateById(zcdHz);
            finashFlg = true;
        }

        // 判断是否为冷藏车的单据，并且是否存在冷藏车内其他单据尚未结束的情况
        if (isCar) {
            notFinishedMx = this.psZcdMxMapper.selectNotFinishedCarMx(zcdNo);
            if (notFinishedMx == null || notFinishedMx.size() < 1) {
                cjIds.add(zcdMxList.get(0).getPointone());
                cjIds.add(zcdMxList.get(0).getPointtwo());
                carIds.add(zcdMxList.get(0).getBoxSn());
            }
        }

        if (cjIds.size() > 0) {
            if (isCar) {
                this.deviceMapper.updateWorkingByIds(cjIds, WorkingStateEnum.未关联.getValue());
            }
            else {
                for (String temp : cjIds) {
                    this.deviceMapper.updateWorkingById(temp, WorkingStateEnum.未关联.getValue(), zcdNo);
                }
            }
        }
        if (lcSns.size() > 0) {
            if (isCar) {
                this.couvenseMapper.updateWorkingByIds(lcSns, WorkingStateEnum.未关联.getValue());
            }
            else {
                for (String temp : lcSns) {
                    this.couvenseMapper.updateWorkingById(temp, WorkingStateEnum.未关联.getValue(), zcdNo);
                }
            }
        }
        if (carIds.size() > 0) {
            this.chillCarMapper.updateWorkingByIds(carIds, WorkingStateEnum.未关联.getValue());
        }

        // 等前面跑完了再发消息处理
        if (finashFlg) {
            // 用来更新LMIS系统的保温箱号和启运温度
            List<LmisZcdMxUpdateVo> lmisZcdMxUpdateVoList = new ArrayList<>();
            // 回传更新LMIS系统的保温箱号和启运温度
            try {
                lmisZcdMxUpdateVoList = this.generateZcdBackInfo(zcdMxList);
                for (LmisZcdMxUpdateVo temp : lmisZcdMxUpdateVoList) {
                    this.psZcdMxMapper.updateLmisZcdMxWithTemp(temp);
                }
            }
            catch (Exception e) {
                logger.error("回传LMIS装车单启运信息失败", e);
            }

            if (zcdNo.startsWith("ZCD") || zcdNo.startsWith("DSF")) {
                return sb.toString();
            }

            OAProducer oAProducer = (OAProducer) SpringContextHolder.getBean("oAProducer");
            oAProducer.sendBackWmsMsg(zcdNo);
        }

        return sb.toString();
    }

    /**
     * 冷藏车关联
     * 1.关联
     * 2.发车
     * @param zhuangcdNos
     * @param chillCarId
     * @param pointOne
     * @param pointTwo
     * @return
     */
    @Override
    public String carRelation(List<String> zhuangcdNos, String chillCarId, String pointOne, String pointTwo) {
        // 定义变量
        Float min = null;
        Float max = null;
        String msgTemplate = null;
        StringBuilder sb = new StringBuilder();
        List<PsZcdHz> psZcdHzList = null;
        List<PsZcdMx> psZcdMxList = null;
        List<TADevice> deviceList = null;
        Timestamp now = new Timestamp(System.currentTimeMillis());
        TAChillCar car = null;
        String useZxChillcar = paramService.getValueByCode("USE_ZX_CHILLCAR");

        // 判断是否冷藏车测点
        car = this.chillCarMapper.selectById(chillCarId);
        if (Constants.Y.equals(useZxChillcar)) {
            if (!car.getMeasurepointOne().equals(pointOne) || !car.getMeasurepointTwo().equals(pointTwo)) {
                sb.append("已启用志祥领域冷藏车，请不要修改车辆测点！");
                return sb.toString();
            }
        }
        else {
            if (car.getMeasurepointOne().equals(pointOne) || car.getMeasurepointTwo().equals(pointTwo)) {
                sb.append("尚未启用志祥领域冷藏车，请选择温湿度采集设备进行关联！");
                return sb.toString();
            }
        }

        // 查询装车单汇总信息，因为前端判断过状态，此处不再做状态上的判断，同理，前端做过空判断，此处不再判断
        psZcdHzList = this.selectBatchIds(zhuangcdNos);
        // 查询装车单明细信息，进行冷藏车关联操作
        psZcdMxList = this.psZcdMxService.selectByZcdNos(zhuangcdNos);

        // 判断是否存在已关联设备，如果存在，则清空原状态
        this.deviceMapper.updateStateByZcdNos(zhuangcdNos, WorkingStateEnum.未关联.getValue());
        this.couvenseMapper.updateStateByZcdNos(zhuangcdNos, WorkingStateEnum.未关联.getValue());
        this.chillCarMapper.updateStateByZcdNos(zhuangcdNos, WorkingStateEnum.未关联.getValue());

        for (PsZcdHz temp : psZcdHzList) {
            // 1:已关联? 亦或 2:激活关联?
            temp.setState(PsStateEnum.已关联.getValue());
        }

        for (PsZcdMx temp : psZcdMxList) {
            temp.setCaozStaff(UserUtils.getUser().getId());
            temp.setCarFlag(WhetherOrNotEnum.是.getValue());
            temp.setBoxSn(chillCarId);
            temp.setPointone(pointOne);
            temp.setPointtwo(pointTwo);
            temp.setSbSn("");
        }

        // 更新状态并保存 设备、冷藏车[3:已关联? 亦或 2:已激活?]
        this.updateBatchById(psZcdHzList);
        this.psZcdMxService.updateBatchById(psZcdMxList);
        this.deviceMapper.updateWorkingByIds(new ArrayList(){{
            add(pointOne);
            add(pointTwo);
        }}, WorkingStateEnum.已关联.getValue());
        this.chillCarMapper.updateWorkingByIds(new ArrayList(){{
            add(chillCarId);
        }}, WorkingStateEnum.已关联.getValue());

        return sb.toString();
    }

    /**
     * 单据作废
     * @param zcdNos
     * @return
     */
    @Override
    public String cancel(List<String> zcdNos) {
        // 变量声明
        Timestamp now = new Timestamp(System.currentTimeMillis());
        List<PsZcdHz> zcdHzList = null;
        List<PsZcdMx> zcdMxList = null;

        // 装车单汇总状态为3:配送完成，上传FLAG置1
        zcdHzList = this.selectBatchIds(zcdNos);
        for (PsZcdHz temp : zcdHzList) {
            temp.setState(PsStateEnum.配送完成.getValue());
            temp.setWdCsFlag(1);
        }
        this.updateBatchById(zcdHzList);

        // 装车单明细开始时间和结束时间设置相同的当前时间，没有设备号和箱号
        zcdMxList = this.psZcdMxMapper.selectByZcdNos(zcdNos);
        for (PsZcdMx temp : zcdMxList) {
            temp.setBoxSn(null);
            temp.setSbSn(null);
            temp.setBeginDate(now);
            temp.setEndDate(now);
        }
        this.psZcdMxService.updateBatchById(zcdMxList);

        return null;
    }

    /**
     * 同步装车单
     * @param zcdNo
     * @return
     */
    @Override
    public String syncZcd(String zcdNo) {
        // 变量定义
        List<String> zcdNos = new ArrayList<>();
        List<PsZcdMx> zcdMxList = null;
        List<PsZcdHz> zcdHzList = null;

        // 判断装车单是否已经存在
        PsZcdHz zcdHz = this.baseMapper.selectById(zcdNo);
        if (zcdHz != null) {
            return "装车单已存在，请确认后重新同步！";
        }

        // 先从视图中获取尚未同步的装车单明细数据
        zcdMxList = this.psZcdMxMapper.getZcdMxFromLmisByZcdNo(zcdNo);

        if (zcdMxList == null || zcdMxList.size() < 1) {
            return "未能找到装车单，请确认后重新同步！";
        }

        // 根据装车单号获取装车单汇总数据
        for (PsZcdMx temp : zcdMxList) {
            if (!zcdNos.contains(temp.getZhuangcdNo())) {
                zcdNos.add(temp.getZhuangcdNo());
            }
        }
        // 逻辑上不可能为空，就不做判断了
        zcdHzList = this.baseMapper.getZcdHzFromLmis(zcdNos);

        // 保存
        this.insertBatch(zcdHzList);
        this.psZcdMxService.insertBatch(zcdMxList);

        return null;
    }

    @Override
    public String back(List<String> zcdNos) {
        StringBuilder sb = new StringBuilder();
        List<PsZcdHz> psZcdHzList = this.selectBatchIds(zcdNos);
        for (PsZcdHz hz : psZcdHzList) {
            if (PsStateEnum.未关联.getValue().equals(hz.getState()) || PsStateEnum.已关联.getValue().equals(hz.getState())) {
                sb.append(hz.getZhuangcdNo()).append(";");
            }
        }

        if (StringUtils.isNotEmpty(sb.toString())) {
            sb.insert(0, "装车单[").append("]未启运，不能反馈启运信息。");
            return sb.toString();
        }

        List<PsZcdMx> psZcdMxList = this.psZcdMxService.selectByZcdNos(zcdNos);

        // 过滤出保温箱装车单和冷藏车装车单
        List<PsZcdMx> allMxList = new ArrayList<>();
        List<String> carMxIdList = new ArrayList<>();
        for (PsZcdMx mx : psZcdMxList) {
            if (StringUtils.isNotEmpty(mx.getBoxNo())) {
                allMxList.add(mx);
            }
            else {
                carMxIdList.add(mx.getZhuangcdNo());
            }
        }

        // 单独查冷藏车的回传信息
        if (carMxIdList != null && carMxIdList.size() > 0) {
            List<PsZcdMx> carMxList = this.psZcdMxService.selectCarMxByZcdNos(carMxIdList);
            allMxList.addAll(carMxList);
        }

        List<BackTemperatureVo> backTemperatureVoList = PsZcdConvert.INSTANCE.psZcdMxToBackTempList(allMxList);
        String token = CQAuthenticationUtils.getAccessToken();
        if (StringUtils.isEmpty(token)) {
            return null;
        }

        // 解析结果
        String sendMailUrl = CQAuthenticationUtils.URL_HOSTNAME + URL_BACK_TEMPERATURE;
        // TODO
        Map<String, String> header = new HashMap<>();
        header.put("accesstoken", token);
        Map param = new HashMap();
        param.put("list", backTemperatureVoList);
        String ret = HttpUtils.httpsPostWithJson(CQAuthenticationUtils.URL_HOSTNAME, sendMailUrl, JSONObject.fromObject(param).toString(), header);
        JSONObject obj = JSONObject.fromObject(ret);

        if (obj == null || obj.size() < 1) {
            logger.error("回传启运温度信息失败!接口返回空！");
            return "回传启运温度信息失败!接口返回空！";
        }
        if (!"200".equals(((JSONObject)obj.get("data")).get("code"))) {
            logger.error("回传启运温度信息失败!({})", obj.toString());
            return "回传启运温度信息失败:" + obj.toString();
        }

        for (PsZcdHz hz : psZcdHzList) {
            hz.setBackFlg(WhetherOrNotEnum.是.getValue());
        }
        PsZcdService.this.updateBatchById(psZcdHzList);

        return null;
    }

    /**
     * API-发车确认
     * 1.首先查看是否存在装车单汇总和明细数据
     * 2.判断装车单状态
     * 3.判断装车单明细是否全部关联
     * 4.更新装车单汇总以及明细信息
     * 5.更新采集设备以及保温箱状态
     * @param zcdNo
     */
    @Override
    public String facConfirmForApi(String zcdNo) {
        // 定义变量
        String msg = null;
        PsZcdHz psZcdHz = null;
        List<PsZcdMx> psZcdMxList = null;

        // 查询装车单信息
        psZcdHz = this.selectById(zcdNo);
        if (psZcdHz == null || !DeliveryStateEnum.确认.getValue().equals(psZcdHz.getDeliveryState())) {
            msg = "未查询到装车单数据";
            return msg;
        }

        // 查询装车单明细
        psZcdMxList = this.psZcdMxService.selectByZcdNos(Arrays.asList(zcdNo));
        if (psZcdMxList == null || psZcdMxList.size() < 1) {
            msg = "未查询到装车单明细数据";
            return msg;
        }

        // 查看装车单状态
        msg = this.psStateCompare(psZcdHz, PsStateEnum.已关联.getValue());
        if (StringUtils.isNotEmpty(msg)) {
            return msg;
        }

        // 检查完之后进行发车确认
        msg = this.facConfirm(new ArrayList<>(Arrays.asList(zcdNo)));
        if (StringUtils.isNotEmpty(msg)) {
            return msg;
        }

        return msg;
    }

    /**
     * API-配送交接
     * 1.首先查看是否存在装车单汇总和明细数据
     * 2.判断装车单状态
     * @param zcdNo
     */
    @Override
    public String handOverForApi(String zcdNo, String address, boolean isWholePsjj) {
        // 变量定义
        StringBuilder sb = new StringBuilder();
        String msg = null;
        PsZcdHz psZcdHz = null;
        List<PsZcdMx> psZcdMxList = null;
        Timestamp handOverDate = null;
        List<String> danjNos = new ArrayList<>();
        List<String> sbSns = new ArrayList<>();
        List<TADevice> deviceList = null;
        Date now = new Date();
        long diff = 0L;

        // 查询装车单信息
        psZcdHz = this.selectById(zcdNo);
        if (psZcdHz == null || !DeliveryStateEnum.确认.getValue().equals(psZcdHz.getDeliveryState())) {
            msg = "未查询到装车单数据";
            return msg;
        }

        // 查看装车单状态
        msg = this.psStateCompare(psZcdHz, PsStateEnum.激活关联.getValue());
        if (StringUtils.isNotEmpty(msg)) {
            return msg;
        }

        // 查询装车单明细
        EntityWrapper<PsZcdMx> wrapper = new EntityWrapper<>();
        wrapper.eq("MX_ZHUANGCD_NO", zcdNo);
        if (isWholePsjj) {
            wrapper.isNull("MX_END_DATE");
            psZcdMxList = this.psZcdMxService.selectList(wrapper);
        } else {
            wrapper.eq("MX_ADDRESS", address);
            psZcdMxList = this.psZcdMxService.selectList(wrapper);
        }

        if (psZcdMxList == null || psZcdMxList.size() < 1) {
            msg = "未查询到装车单明细数据";
            return msg;
        }

        // 查询出来需要配送交接的单据编号
        for (PsZcdMx temp : psZcdMxList) {
            if (!danjNos.contains(temp.getDanjNo())) {
                danjNos.add(temp.getDanjNo());
            }
            if (!sbSns.contains(temp.getSbSn())) {
                sbSns.add(temp.getSbSn());
            }
        }

        // 配送交接前的检查工作
        msg = this.beforeHandOver(zcdNo, handOverDate, danjNos);
        if (StringUtils.isNotEmpty(msg)) {
            return msg.substring(0, msg.indexOf("<font"));
        }
        // 由于微信小程序不能选择交接时间，故API通过获取设备的最新时间作为交接时间
        psZcdMxList = this.psZcdMxMapper.selectZcdMxTempByDanjNo(danjNos, null);
        handOverDate = psZcdMxList.get(0).getCollectTime();

        for (PsZcdMx temp : psZcdMxList) {
            diff = DateUtils.getSecondOfTwoDate(temp.getCollectTime(), now);
            if ((diff / 60) > 4) {
                sb.append("关联设备[").append(temp.getSbNo()).append("]最新采集时间为[")
                        .append(DateUtils.formatDate(temp.getCollectTime(), "yyyy-MM-dd HH:mm:ss"))
                        .append("]，请重新确认交接时间！");
                return sb.toString();
            }
        }


        // 真正的配送交接工作
        msg = this.handOver(zcdNo, handOverDate, danjNos);
        if (StringUtils.isNotEmpty(msg)) {
            return msg;
        }

        return sb.toString();
    }

    /**
     * 比较装车单与标准状态是否一致
     * @param zcdHz
     * @param standardState
     * @return
     */
    @Override
    public String psStateCompare(PsZcdHz zcdHz, String standardState) {
        String ret = null;

        if (standardState.equals(zcdHz.getState())) {
            return ret;
        }

        // 判断装车单状态
        if (PsStateEnum.未关联.getValue().equals(zcdHz.getState())) {
            ret = zcdHz.getZhuangcdNo() + "未装箱关联";

        } else if (PsStateEnum.已关联.getValue().equals(zcdHz.getState())) {
            ret = zcdHz.getZhuangcdNo() + "已关联未激活";

        } else if (PsStateEnum.激活关联.getValue().equals(zcdHz.getState())) {
            ret = zcdHz.getZhuangcdNo() + "已激活关联";

        } else if (PsStateEnum.配送完成.getValue().equals(zcdHz.getState())) {
            ret = zcdHz.getZhuangcdNo() + "已配送完成";
        }

        return ret;

    }

    @Override
    public CkdInfo queryCkdInfo(String liushBarcode) {
        StringBuilder sb = new StringBuilder();

        // 根据流水号查询LMIS查出来业务单据编号
        String sql = "SELECT DISTINCT HZ.YEWDJ_NO, HZ.YEW_STAFF, HZ.SJ_SJ_DANJ_NO FROM VIW_CK_KPD_HZ HZ INNER JOIN VIW_YW_XJZL ZL ON HZ.DANJ_NO = ZL.DANJ_NO WHERE HZ.YEWDJ_NO = ? OR ZL.LIUSH_BARCODE = ?";
        List<Map<String, Object>> infos = DynamicDBUtils.getDynamicDBDao("LMIS").queryList(sql, liushBarcode, liushBarcode);
        if (infos == null || infos.size() < 1) {
            return null;
        }

        // 再根据业务单据编号查询对应的流程信息
        CkdInfo ckdInfo = convertCkdInfo(infos.get(0));
        // SG0000451347-SG0000352362-SG0000451348
        sql = "SELECT * FROM fv_get_SPD_LOG(?)";
        List<Map<String, Object>> ckdProcessList = DynamicDBUtils.getDynamicDBDao("ERP").queryList(sql, ckdInfo.getStockioId());
        if (ckdProcessList == null || ckdProcessList.size() < 1) {
            return ckdInfo;
        }

        this.putProcessIntoCkdInfo(ckdInfo, ckdProcessList);

        return ckdInfo;
    }

    /**
     * MAP转换为CkdInfo类
     * @param map
     * @return
     */
    private CkdInfo convertCkdInfo(Map<String, Object> map) {
        CkdInfo ckdInfo = new CkdInfo();

        ckdInfo.setStockioId((String) map.get("YEWDJ_NO"));
        ckdInfo.setYewStaff((String) map.get("YEW_STAFF"));
        ckdInfo.setPlatformNo((String) map.get("SJ_SJ_DANJ_NO"));

        return ckdInfo;
    }

    /**
     * MAP转换为CkdProcess列表并写入CkdInfo中
     * @param ckdInfo
     * @param list
     * @return
     */
    private CkdInfo putProcessIntoCkdInfo(CkdInfo ckdInfo, List<Map<String, Object>> list) {
        List<CkdProcess> ckdProcessList = new ArrayList<>();
        CkdProcess ckdProcess = null;
        // 将客户编码与客户名称放入主表信息中
        ckdInfo.setCust((String) list.get(0).get("cust"));
        ckdInfo.setCustName((String) list.get(0).get("cust_name"));

        // 遍历生成流程信息
        for (Map<String, Object> map : list) {
            ckdProcess = new CkdProcess();
            String type = (String) map.get("TYPE");
            ckdProcess.setStockioId((String) map.get("stockio_id"));
            ckdProcess.setCust((String) map.get("cust"));
            ckdProcess.setCustName((String) map.get("cust_name"));
            ckdProcess.setType(type.substring(3, type.length()).replace("时间", ""));
            ckdProcess.setDtime((Date) map.get("DTIME"));
            ckdProcess.setNo(type.substring(0, 2));
            ckdProcessList.add(ckdProcess);

            // 判断关键节点发货单上传与发票信息上传
            if("07".equals(ckdProcess.getNo())) {
                if (ckdProcess.getDtime() == null) {
                    ckdInfo.setCkdUploadFlg(false);
                } else {
                    ckdInfo.setCkdUploadFlg(true);
                    ckdInfo.setCkdUploadTime(ckdProcess.getDtime());
                }
            } else if ("15".equals(ckdProcess.getNo())) {
                if (ckdProcess.getDtime() == null) {
                    ckdInfo.setInvoiceUploadFlg(false);
                } else {
                    ckdInfo.setInvoiceUploadFlg(true);
                    ckdInfo.setInvoiceUploadTime(ckdProcess.getDtime());
                }
            }
        }

        ckdInfo.setCkdProcessList(ckdProcessList);
        return ckdInfo;

    }

    /**
     * 生成需要回传LMIS得装车单信息
     * @param psZcdMxList
     * @return
     */
    private List<LmisZcdMxUpdateVo> generateZcdBackInfo(List<PsZcdMx> psZcdMxList) {
        boolean exists = false;
        String danjNo = null;
        LmisZcdMxUpdateVo lmisZcdMxUpdateVo = null;
        List<LmisZcdMxUpdateVo> lmisZcdMxUpdateVoList = new ArrayList<>();

        for (PsZcdMx temp : psZcdMxList) {
            if(!temp.getZhuangcdNo().startsWith("ZCD")) {
                continue;
            }
            exists = false;
            danjNo = temp.getDanjNo();
            for (LmisZcdMxUpdateVo zcdMxUpdateVo : lmisZcdMxUpdateVoList) {
                if (danjNo.equals(zcdMxUpdateVo.getDanjNo())) {
                    exists = true;
                    lmisZcdMxUpdateVo = zcdMxUpdateVo;
                    break;
                }
            }
            if (exists) {
                if (lmisZcdMxUpdateVo.getBoxSn().indexOf(temp.getBoxNo()) < 0) {
                    lmisZcdMxUpdateVo.setBoxSn(lmisZcdMxUpdateVo.getBoxSn() + ',' + temp.getBoxSn());
                    lmisZcdMxUpdateVo.setTemperature(lmisZcdMxUpdateVo.getTemperature() + ',' + temp.getTemperature());
                }
            } else {
                lmisZcdMxUpdateVo = new LmisZcdMxUpdateVo();
                lmisZcdMxUpdateVo.setZhuangcdNo(temp.getZhuangcdNo());
                lmisZcdMxUpdateVo.setDanjNo(danjNo);
                lmisZcdMxUpdateVo.setBoxSn(temp.getBoxNo());
                lmisZcdMxUpdateVo.setHuozId(temp.getHuozId());
                lmisZcdMxUpdateVo.setTemperature(String.valueOf(temp.getTemperature()));
                lmisZcdMxUpdateVoList.add(lmisZcdMxUpdateVo);
            }
        }

        return lmisZcdMxUpdateVoList;
    }


}
